package middleware

import (
	"encoding/json"
	"errors"
	"fmt"
	"git.mycaigou.com/gfyx/common/authorize"
	"git.mycaigou.com/gfyx/common/cache"
	"git.mycaigou.com/gfyx/common/rpc_client"
	"git.mycaigou.com/gfyx/micro-gfyx-api/infrastructure/common/errcode"
	"git.mycaigou.com/gfyx/micro-gfyx-api/infrastructure/di"
	userRepo "git.mycaigou.com/gfyx/micro-gfyx-api/infrastructure/repository/base/user"
	"git.mycaigou.com/gfyx/micro-gfyx-api/infrastructure/utils"
	"git.mycaigou.com/gfyx/micro-gfyx-api/service/base/user"
	"git.myscrm.cn/golang/stark/v4"
	"github.com/gin-gonic/gin"
	"net/http"
)

var (
	error_lack_authorization = "请求头缺少token字段"
)

func response(ctx *gin.Context, errorCode int, msg string) {
	result := gin.H{
		"success":    false,
		"message":    msg,
		"error_code": errorCode,
		"data":       nil,
	}

	ctx.JSON(http.StatusOK, result)
	ctx.Abort()
}

type HttpHeader struct {
	AuthToken string `json:"auth-token"`
}

// Authorize
// middleware
func Authorize(excludes []string) gin.HandlerFunc {
	return func(ctx *gin.Context) {
		// 排除鉴权的路由
		if utils.InArray(excludes, ctx.Request.URL.Path) {
			ctx.Next()
			return
		}
		token := ctx.Request.Header.Get("token")
		if token == "" {
			response(ctx, errcode.COMMON_USER_IDENTITY_ERROR, error_lack_authorization)
			return
		}

		// 写入缓存
		cacheRedis, _ := cache.Redis()
		cacheKey := fmt.Sprintf("gfyx-pc-%s", token)
		cacheTokenWithUserInfoVal, err := cacheRedis.Get(ctx, cacheKey)
		//cacheTokenWithUserInfoVal = ""
		if err != nil {
			stark.Logger.Errorf(ctx, "Authorize-cache: %s, value: %v, err: %+v", cacheKey, cacheTokenWithUserInfoVal, err)
		}

		readCacheUserInfoSuccess := false
		userInfo := &userRepo.UserInfo{}
		if cacheTokenWithUserInfoVal != "" {
			// 读取缓存
			err = json.Unmarshal([]byte(cacheTokenWithUserInfoVal), &userInfo)
			if err != nil {
				readCacheUserInfoSuccess = false
				stark.Logger.Errorf(ctx, "Authorize-json.Unmarshal %s, value: %v, err: %+v", cacheKey, cacheTokenWithUserInfoVal, err)
			} else {
				readCacheUserInfoSuccess = true
			}
		}
		if readCacheUserInfoSuccess == false {
			// 远程调用鉴权获取用户信息
			c := di.InjectInstance()
			err = c.Invoke(func(userService user.UserSerivceIface) error {
				// 注意！！这里不用 :=赋值
				userInfo, _, err = userService.VerifyToken(ctx, token)
				if err != nil {
					stark.Logger.Errorf(ctx, "Authorize-VerifyToken token:%s, err: %+v", token, err)
					return err
				}

				if userInfo == nil {
					stark.Logger.Errorf(ctx, "Authorize-VerifyToken userinfo empty", "")
					return errors.New("用户不存在")
				}

				userInfoJsonByte, err := json.Marshal(userInfo)
				if err != nil {
					stark.Logger.Errorf(ctx, "Authorize-json.Marshal %s, value: %v, err: %+v", cacheKey, userInfo, err)
				} else {
					// 存储 JSON 字符串到 Redis，缓存1分钟
					_, err = cacheRedis.Set(ctx, cacheKey, string(userInfoJsonByte), true, 1*60)
					if err != nil {
						stark.Logger.Errorf(ctx, "Authorize-cacheRedis.Set %s, value: %v, err: %+v", cacheKey, userInfo, err)
					}
				}
				stark.Logger.Infof(ctx, "Authorize-success: %s, globalUserUid: %s", token, userInfo.Uid)
				return nil
			})
			if err != nil {
				grpcErr := rpc_client.GetGrpcError(err)
				errCode := errcode.COMMON_USER_IDENTITY_ERROR
				errMessage := err.Error()

				if grpcErr != nil && grpcErr.GetCode() == 20020001 {
					errCode = errcode.COMMON_USER_FORBIDDEN
					errMessage = grpcErr.GetMessage()
				}

				stark.Logger.Infof(ctx, "Authorize-token: %s, err: %+v", token, err)
				response(ctx, errCode, errMessage)
				return
			}
		}
		//用户态写入上下文
		authorize.SetLoginContext(ctx, userInfo.Uid, userInfo.TenantCode, userInfo.UserCode, userInfo.TenantUserUid, userInfo.UserName, userInfo.Mobile, userInfo.TenantName)

		ctx.Next()
	}
}

// SyncUserAuthorize
// 用户同步验证
func SyncUserAuthorize() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		authToken := ctx.Request.Header.Get("auth_token")
		syncuserAuthToken := stark.Configer.(stark.ApolloConfigerIface).GetStringValue("syncuser_auth_token", "")
		if authToken != syncuserAuthToken {
			stark.Logger.Warnf(ctx, "token验证失败，auth_token: %s", authToken)
			response(ctx, errcode.COMMON_TOKEN_ERROR, "token验证失败")
			return
		}
		ctx.Next()
	}
}
